package com.own.component.util.locate.util;

import com.own.component.util.locate.model.LocateModel;

import java.math.BigDecimal;

/**
 * LocateDistanceCircleConvertUtil
 *
 * @author chenxueli
 * @date 2024-05-13 11:21:41
 */
public class LocateDistanceCircleConvertUtil {

    /**
     * 计算有没有超出范围
     *
     * @param latitude1  圆心纬度
     * @param longitude1 圆心经度
     * @param latitude2  目标纬度
     * @param longitude2 目标经度
     * @param distance   半径
     * @return 是否超出范围
     */
    public static boolean checkOut(
            double latitude1, double longitude1,
            double latitude2, double longitude2,
            BigDecimal distance
    ) {
        // 获取两点对象
        var x = new LocateModel(latitude1, longitude1);
        var y = new LocateModel(latitude2, longitude2);
        return checkOut(x, y, distance);
    }

    /**
     * 计算有没有超出范围
     *
     * @param latitude1  圆心纬度
     * @param longitude1 圆心经度
     * @param latitude2  目标纬度
     * @param longitude2 目标经度
     * @param distance   半径
     * @return 是否超出范围
     */
    public static boolean checkOut(
            BigDecimal latitude1, BigDecimal longitude1,
            BigDecimal latitude2, BigDecimal longitude2,
            BigDecimal distance
    ) {
        // 获取两点对象
        var x = new LocateModel(latitude1, longitude1);
        var y = new LocateModel(latitude2, longitude2);
        return checkOut(x, y, distance);
    }

    /**
     * 计算有没有超出范围
     *
     * @param x        圆心坐标
     * @param y        目标坐标
     * @param distance 半径
     * @return 是否超出范围
     */
    public static boolean checkOut(LocateModel x, LocateModel y, BigDecimal distance) {
        // 计算两点之间的距离
        var realDistance = LocateDistanceUtil.calc(x, y);
        // 判断是否超出范围
        return realDistance.compareTo(distance) > 0;
    }

    /**
     * 获取最近的点
     *
     * @param latitude1  圆心纬度
     * @param longitude1 圆心经度
     * @param latitude2  目标纬度
     * @param longitude2 目标经度
     * @param distance   半径
     * @return 最近的点
     */
    public static LocateModel getNearest(
            double latitude1, double longitude1,
            double latitude2, double longitude2,
            BigDecimal distance
    ) {
        // 获取两点对象
        var x = new LocateModel(latitude1, longitude1);
        var y = new LocateModel(latitude2, longitude2);
        return getNearest(x, y, distance);
    }

    /**
     * 获取最近的点
     *
     * @param latitude1  圆心纬度
     * @param longitude1 圆心经度
     * @param latitude2  目标纬度
     * @param longitude2 目标经度
     * @param distance   半径
     * @return 最近的点
     */
    public static LocateModel getNearest(
            BigDecimal latitude1, BigDecimal longitude1,
            BigDecimal latitude2, BigDecimal longitude2,
            BigDecimal distance
    ) {
        // 获取两点对象
        var x = new LocateModel(latitude1, longitude1);
        var y = new LocateModel(latitude2, longitude2);
        return getNearest(x, y, distance);
    }

    /**
     * 计算又没有超出范围
     *
     * @param x        圆心坐标
     * @param y        目标坐标
     * @param distance 半径
     * @return 是否超出范围
     */
    public static LocateModel getNearest(LocateModel x, LocateModel y, BigDecimal distance) {
        var flag = checkOut(x, y, distance);
        if (!flag) {
            return y;
        }
        // 计算圆心与目标地址之间的方向向量
        double directionLat = y.getLatitude().doubleValue() - x.getLatitude().doubleValue();
        double directionLong = y.getLongitude().doubleValue() - x.getLongitude().doubleValue();
        // 将方向向量归一化
        double magnitude = Math.sqrt(directionLat * directionLat + directionLong * directionLong);
        directionLat /= magnitude;
        directionLong /= magnitude;
        // 计算圆上最近点的经纬度坐标
        double nearestLat = x.getLatitude().doubleValue() + directionLat * distance.doubleValue();
        double nearestLong = x.getLongitude().doubleValue() + directionLong * distance.doubleValue();
        return new LocateModel(nearestLat, nearestLong);
    }

}
